/*-------------------------------------------------------------------------
 *
 * execExpr.h
 *	  与表达式评估相关的低级基础设施
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/executor/execExpr.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef EXEC_EXPR_H
#define EXEC_EXPR_H

#include "executor/nodeAgg.h"
#include "nodes/execnodes.h"

/* 向前引用以避免循环 */
struct ExprEvalStep;
struct SubscriptingRefState;
struct ScalarArrayOpExprHashTable;

/* ExprState->flags 中的位（另见 execnodes.h 中的公共标志位）： */
/* 表达式的解释器已初始化 */
#define EEO_FLAG_INTERPRETER_INITIALIZED	(1 << 1)
/* 使用了跳转线程 */
#define EEO_FLAG_DIRECT_THREADED			(1 << 2)

/* 典型的离线评估子例程API */
typedef void (*ExecEvalSubroutine) (ExprState *state,
									struct ExprEvalStep *op,
									ExprContext *econtext);

/* 返回 bool 的离线评估子例程的 API */
typedef bool (*ExecEvalBoolSubroutine) (ExprState *state,
										struct ExprEvalStep *op,
										ExprContext *econtext);

/* 缓存复合类型 tupdesc 的 ExprEvalSteps 需要其中之一 */
/* （它可以适合某些步骤类型的内联，否则分配到外部） */
typedef struct ExprEvalRowtypeCache
{
	/*
	 * cacheptr 指向复合类型的 TypeCacheEntry，如果 tupdesc_id 不为
	 * 0；或者对于一个匿名 RECORD 类型，它指向该类型的缓存
	 * tupdesc，且 tupdesc_id 为 0。 （如果空间不是紧张的话，我们会使用单独的字段。）
	 * 初始状态是 cacheptr == NULL。
	 */
	void	   *cacheptr;
	uint64		tupdesc_id;		/* 最近看到的 tupdesc 标识符，或 0 */
} ExprEvalRowtypeCache;

/*
 * ExprEvalSteps 的区分符。
 *
 * 确定要执行的操作以及 ExprEvalStep->d 联合体中哪个成员是有效的。
 *
 * 条目的顺序需要与 execExprInterp.c:ExecInterpExpr() 中的 dispatch_table[]
 * 数组保持同步。
 */
typedef enum ExprEvalOp
{
	/* 整个表达式已完全评估，返回 */
	EEOP_DONE,

	/* 在相应的元组槽上应用 slot_getsomeattrs */
	EEOP_INNER_FETCHSOME,
	EEOP_OUTER_FETCHSOME,
	EEOP_SCAN_FETCHSOME,

	/* 计算非系统 Var 值 */
	EEOP_INNER_VAR,
	EEOP_OUTER_VAR,
	EEOP_SCAN_VAR,

	/* 计算系统 Var 值 */
	EEOP_INNER_SYSVAR,
	EEOP_OUTER_SYSVAR,
	EEOP_SCAN_SYSVAR,

	/* 计算整行 Var */
	EEOP_WHOLEROW,

	/*
	 * 计算非系统变量值，将其赋值到ExprState的结果槽中。
	 * 如果需要进行CheckVarSlotCompatibility()检查，则这些不会被使用。
	 */
	EEOP_ASSIGN_INNER_VAR,
	EEOP_ASSIGN_OUTER_VAR,
	EEOP_ASSIGN_SCAN_VAR,

	/* 将 ExprState 的 resvalue/resnull 分配给其结果槽的列 */
	EEOP_ASSIGN_TMP,
	/* 同上，应用 MakeExpandedObjectReadOnly() */
	EEOP_ASSIGN_TMP_MAKE_RO,

	/* 评估 Const 值 */
	EEOP_CONST,

	/*
	 * 评估函数调用（包括 OpExprs 等）。为了提高速度，我们
	 * 在操作码中区分函数是否严格和/或需要使用统计跟踪。
	 */
	EEOP_FUNCEXPR,
	EEOP_FUNCEXPR_STRICT,
	EEOP_FUNCEXPR_FUSAGE,
	EEOP_FUNCEXPR_STRICT_FUSAGE,

	/*
	 * 评估布尔 AND 表达式，每个子表达式一步。FIRST/LAST
	 * 子表达式针对性能进行了特殊处理。由于 AND 始终具有
	 * 至少两个子表达式，FIRST 和 LAST 永远不会应用于同一个
	 * 子表达式。
	 */
	EEOP_BOOL_AND_STEP_FIRST,
	EEOP_BOOL_AND_STEP,
	EEOP_BOOL_AND_STEP_LAST,

	/* 同样适用于布尔 OR 表达式 */
	EEOP_BOOL_OR_STEP_FIRST,
	EEOP_BOOL_OR_STEP,
	EEOP_BOOL_OR_STEP_LAST,

	/* 评估布尔 NOT 表达式 */
	EEOP_BOOL_NOT_STEP,

	/* BOOL_AND_STEP 的简化版本，用于 ExecQual() */
	EEOP_QUAL,

	/* 无条件跳转到另一个步骤 */
	EEOP_JUMP,

	/* 根据当前结果值进行条件跳转 */
	EEOP_JUMP_IF_NULL,
	EEOP_JUMP_IF_NOT_NULL,
	EEOP_JUMP_IF_NOT_TRUE,

	/* 对标量值执行 NULL 测试 */
	EEOP_NULLTEST_ISNULL,
	EEOP_NULLTEST_ISNOTNULL,

	/* 对行值执行 NULL 测试 */
	EEOP_NULLTEST_ROWISNULL,
	EEOP_NULLTEST_ROWISNOTNULL,

	/* 评估 BooleanTest 表达式 */
	EEOP_BOOLTEST_IS_TRUE,
	EEOP_BOOLTEST_IS_NOT_TRUE,
	EEOP_BOOLTEST_IS_FALSE,
	EEOP_BOOLTEST_IS_NOT_FALSE,

	/* 评估 PARAM_EXEC/EXTERN 参数 */
	EEOP_PARAM_EXEC,
	EEOP_PARAM_EXTERN,
	EEOP_PARAM_CALLBACK,

	/* 返回 CaseTestExpr 值 */
	EEOP_CASE_TESTVAL,

	/* 对目标值应用 MakeExpandedObjectReadOnly() */
	EEOP_MAKE_READONLY,

	/* 评估各种特殊用途的表达式类型 */
	EEOP_IOCOERCE,
	EEOP_DISTINCT,
	EEOP_NOT_DISTINCT,
	EEOP_NULLIF,
	EEOP_SQLVALUEFUNCTION,
	EEOP_CURRENTOFEXPR,
	EEOP_NEXTVALUEEXPR,
	EEOP_ARRAYEXPR,
	EEOP_ARRAYCOERCE,
	EEOP_ROW,

	/*
	 * 比较两个比较的 ROW() 表达式的两个单独元素。 
	 * 如果元素不相等，则跳转到 ROWCOMPARE_FINAL。
	 */
	EEOP_ROWCOMPARE_STEP,

	/* 基于之前 ROWCOMPARE_STEP 操作评估布尔值 */
	EEOP_ROWCOMPARE_FINAL,

	/* 评估 GREATEST() 或 LEAST() */
	EEOP_MINMAX,

	/* 评估 FieldSelect 表达式 */
	EEOP_FIELDSELECT,

	/*
	 * 在评估 FieldStore 表达式中单个字段的新值之前，
	 * 先变形元组。
	 */
	EEOP_FIELDSTORE_DEFORM,

	/*
	 * 为 FieldStore 表达式形成新的元组。单个字段将在
	 * 由前面的 DEFORM 步骤变形的元组列中进行评估。
	 */
	EEOP_FIELDSTORE_FORM,

	/* 处理容器下标；可能将结果短路至 NULL */
	EEOP_SBSREF_SUBSCRIPTS,

	/*
	 * 当 SubscriptingRef 赋值
	 * 表达式包含 SubscriptingRef/FieldStore 子表达式时，
	 * 计算旧容器元素/切片。通过 CaseTest 机制访问值。
	 */
	EEOP_SBSREF_OLD,

	/* 计算 SubscriptingRef 赋值表达式的新值 */
	EEOP_SBSREF_ASSIGN,

	/* 计算 SubscriptingRef 获取表达式的元素/切片 */
	EEOP_SBSREF_FETCH,

	/* 评估 CoerceToDomainValue 的值 */
	EEOP_DOMAIN_TESTVAL,

	/* 评估域的 NOT NULL 约束 */
	EEOP_DOMAIN_NOTNULL,

	/* 评估单个域 CHECK 约束 */
	EEOP_DOMAIN_CHECK,

	/* 评估各种特殊用途的表达式类型 */
	EEOP_CONVERT_ROWTYPE,
	EEOP_SCALARARRAYOP,
	EEOP_HASHED_SCALARARRAYOP,
	EEOP_XMLEXPR,
	EEOP_AGGREF,
	EEOP_GROUPING_FUNC,
	EEOP_WINDOW_FUNC,
	EEOP_SUBPLAN,

	/* 聚合相关节点 */
	EEOP_AGG_STRICT_DESERIALIZE,
	EEOP_AGG_DESERIALIZE,
	EEOP_AGG_STRICT_INPUT_CHECK_ARGS,
	EEOP_AGG_STRICT_INPUT_CHECK_NULLS,
	EEOP_AGG_PLAIN_PERGROUP_NULLCHECK,
	EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL,
	EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL,
	EEOP_AGG_PLAIN_TRANS_BYVAL,
	EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF,
	EEOP_AGG_PLAIN_TRANS_STRICT_BYREF,
	EEOP_AGG_PLAIN_TRANS_BYREF,
	EEOP_AGG_ORDERED_TRANS_DATUM,
	EEOP_AGG_ORDERED_TRANS_TUPLE,

	/* 不存在的操作，例如用于检查数组长度 */
	EEOP_LAST
} ExprEvalOp;


typedef struct ExprEvalStep
{
	/*
	 * 要执行的指令。在指令准备期间，它是一个
	 * 枚举 ExprEvalOp，但之后可以更改为其他类型，例如计算跳转的指针
	 * （这就是为什么它是一个intptr_t）。
	 */
	intptr_t	opcode;

	/* 存储此步骤结果的位置 */
	Datum	   *resvalue;
	bool	   *resnull;

	/*
	 * 操作的内联数据。内联数据访问速度更快，但
	 * 也会增加所有指令的大小。在64位系统上，联合体的大小应保持在
	 * 不超过40字节（这样整个结构的大小不超过64字节，在常见系统中为单个缓存行）。
	 */
	union
	{
		/* 用于 EEOP_INNER/OUTER/SCAN_FETCHSOME */
		struct
		{
			/* 需要获取的属性编号（含） */
			int			last_var;
			/* 每次调用的槽类型是否相同 */
			bool		fixed;
			/* tuple 描述符，如果已知 */
			TupleDesc	known_desc;
			/* 槽的类型，只有在设置为固定时才能依赖 */
			const TupleTableSlotOps *kind;
		}			fetch;

		/* 用于 EEOP_INNER/OUTER/SCAN_[SYS]VAR[_FIRST] */
		struct
		{
			/* attnum 是常规 VAR 的属性编号减去1... */
			/* 但对于 SYSVAR，它只是正常（负）的属性编号 */
			int			attnum;
			Oid			vartype;	/* 变量的类型 OID */
		}			var;

		/* 用于 EEOP_WHOLEROW */
		struct
		{
			Var		   *var;	/* 计划树中的原始 Var 节点 */
			bool		first;	/* 第一次通过，需要初始化吗？ */
			bool		slow;	/* 需要运行时检查空值吗？ */
			TupleDesc	tupdesc;	/* 结果元组的描述符 */
			JunkFilter *junkFilter; /* JunkFilter 用于删除 resjunk 列 */
		}			wholerow;

		/* 用于 EEOP_ASSIGN_*_VAR */
		struct
		{
			/* 在 ExprState->resultslot->tts_values/nulls 中的目标索引 */
			int			resultnum;
			/* 源属性编号 - 1 */
			int			attnum;
		}			assign_var;

		/* 用于 EEOP_ASSIGN_TMP[_MAKE_RO] */
		struct
		{
			/* 在 ExprState->resultslot->tts_values/nulls 中的目标索引 */
			int			resultnum;
		}			assign_tmp;

		/* 用于 EEOP_CONST */
		struct
		{
			/* 常量的值 */
			Datum		value;
			bool		isnull;
		}			constval;

		/* 用于 EEOP_FUNCEXPR_* / NULLIF / DISTINCT */
		struct
		{
			FmgrInfo   *finfo;	/* 函数的查找数据 */
			FunctionCallInfo fcinfo_data;	/* 参数等 */
			/* 无需额外间接访问的更快访问方式： */
			PGFunction	fn_addr;	/* 实际调用地址 */
			int			nargs;	/* number of arguments */
			bool		make_ro;	/* 使 arg0 为读/只读（仅用于 NULLIF） */
		}			func;

		/* 用于 EEOP_BOOL_*_STEP */
		struct
		{
			bool	   *anynull;	/* 跟踪是否有输入为 NULL */
			int			jumpdone;	/* 当结果确定时跳转到这里 */
		}			boolexpr;

		/* 针对 EEOP_QUAL */
		struct
		{
			int			jumpdone;	/* 当为 false 或 null 时跳转到这里 */
		}			qualexpr;

		/* 针对 EEOP_JUMP[_CONDITION] */
		struct
		{
			int			jumpdone;	/* 目标指令的索引 */
		}			jump;

		/* 针对 EEOP_NULLTEST_ROWIS[NOT]NULL */
		struct
		{
			/* 复合类型的缓存描述符 - 在运行时填充 */
			ExprEvalRowtypeCache rowcache;
		}			nulltest_row;

		/* 针对 EEOP_PARAM_EXEC/EXTERN */
		struct
		{
			int			paramid;	/* 参数的数字 ID */
			Oid			paramtype;	/* 参数数据类型的 OID */
		}			param;

		/* 针对 EEOP_PARAM_CALLBACK */
		struct
		{
			ExecEvalSubroutine paramfunc;	/* 附加评估子例程 */
			void	   *paramarg;	/* 相同内容的私有数据 */
			int			paramid;	/* 参数的数字 ID */
			Oid			paramtype;	/* 参数数据类型的 OID */
		}			cparam;

		/* 针对 EEOP_CASE_TESTVAL/DOMAIN_TESTVAL */
		struct
		{
			Datum	   *value;	/* 要返回的值 */
			bool	   *isnull;
		}			casetest;

		/* 针对 EEOP_MAKE_READONLY */
		struct
		{
			Datum	   *value;	/* 要强制为只读的值 */
			bool	   *isnull;
		}			make_readonly;

		/* 针对 EEOP_IOCOERCE */
		struct
		{
			/* 源类型输出函数的查找和调用信息 */
			FmgrInfo   *finfo_out;
			FunctionCallInfo fcinfo_data_out;
			/* 结果类型输入函数的查找和调用信息 */
			FmgrInfo   *finfo_in;
			FunctionCallInfo fcinfo_data_in;
		}			iocoerce;

		/* 针对 EEOP_SQLVALUEFUNCTION */
		struct
		{
			SQLValueFunction *svf;
		}			sqlvaluefunction;

		/* 针对 EEOP_NEXTVALUEEXPR */
		struct
		{
			Oid			seqid;
			Oid			seqtypid;
		}			nextvalueexpr;

		/* 针对 EEOP_ARRAYEXPR */
		struct
		{
			Datum	   *elemvalues; /* 元素值存储在这里 */
			bool	   *elemnulls;
			int			nelems; /* 上述数组的长度 */
			Oid			elemtype;	/* 数组元素类型 */
			int16		elemlength; /* 数组元素类型的 typlen */
			bool		elembyval;	/* 元素类型是值传递吗？ */
			char		elemalign;	/* 元素类型的 typalign */
			bool		multidims;	/* 数组表达式是多维吗？ */
		}			arrayexpr;

		/* 针对 EEOP_ARRAYCOERCE */
		struct
		{
			ExprState  *elemexprstate;	/* 如果没有每个元素的工作则为null */
			Oid			resultelemtype; /* 结果数组的元素类型 */
			struct ArrayMapState *amstate;	/* array_map的工作区 */
		}			arraycoerce;

		/* 对于EEOP_ROW */
		struct
		{
			TupleDesc	tupdesc;	/* 结果元组的描述符 */
			/* 组成行的值的工作区： */
			Datum	   *elemvalues;
			bool	   *elemnulls;
		}			row;

		/* 对于EEOP_ROWCOMPARE_STEP */
		struct
		{
			/* 列比较函数的查找和调用数据 */
			FmgrInfo   *finfo;
			FunctionCallInfo fcinfo_data;
			PGFunction	fn_addr;
			/* 比较结果为NULL的目标 */
			int			jumpnull;
			/* 产生不等的比较目标 */
			int			jumpdone;
		}			rowcompare_step;

		/* 对于EEOP_ROWCOMPARE_FINAL */
		struct
		{
			RowCompareType rctype;
		}			rowcompare_final;

		/* 对于EEOP_MINMAX */
		struct
		{
			/* 参数值的工作区 */
			Datum	   *values;
			bool	   *nulls;
			int			nelems;
			/* 是GREATEST还是LEAST？ */
			MinMaxOp	op;
			/* 比较函数的查找和调用数据 */
			FmgrInfo   *finfo;
			FunctionCallInfo fcinfo_data;
		}			minmax;

		/* 对于EEOP_FIELDSELECT */
		struct
		{
			AttrNumber	fieldnum;	/* 要提取的字段号 */
			Oid			resulttype; /* 字段的类型 */
			/* 复合类型的缓存描述符 - 在运行时填充 */
			ExprEvalRowtypeCache rowcache;
		}			fieldselect;

		/* 对于EEOP_FIELDSTORE_DEFORM / FIELDSTORE_FORM */
		struct
		{
			/* 原始表达式节点 */
			FieldStore *fstore;

			/* 复合类型的缓存描述符 - 在运行时填充 */
			/* 注意DEFORM和FORM配对共享相同的缓存 */
			ExprEvalRowtypeCache *rowcache;

			/* 列值的工作区 */
			Datum	   *values;
			bool	   *nulls;
			int			ncolumns;
		}			fieldstore;

		/* 对于EEOP_SBSREF_SUBSCRIPTS */
		struct
		{
			ExecEvalBoolSubroutine subscriptfunc;	/* 评估子例程 */
			/* 太大而无法内联 */
			struct SubscriptingRefState *state;
			int			jumpdone;	/* 在 NULL 时跳转这里 */
		}			sbsref_subscript;

		/* 对于EEOP_SBSREF_OLD / ASSIGN / FETCH */
		struct
		{
			ExecEvalSubroutine subscriptfunc;	/* 评估子例程 */
			/* 太大而无法内联 */
			struct SubscriptingRefState *state;
		}			sbsref;

		/* 对于EEOP_DOMAIN_NOTNULL / DOMAIN_CHECK */
		struct
		{
			/* 约束的名称 */
			char	   *constraintname;
			/* CHECK约束结果将存储的位置 */
			Datum	   *checkvalue;
			bool	   *checknull;
			/* 域类型的OID */
			Oid			resulttype;
		}			domaincheck;

		/* 对于EEOP_CONVERT_ROWTYPE */
		struct
		{
			Oid			inputtype;	/* 输入复合类型 */
			Oid			outputtype; /* 输出复合类型 */
			/* 这三个字段在运行时填写： */
			ExprEvalRowtypeCache *incache;	/* 输入类型的缓存 */
			ExprEvalRowtypeCache *outcache; /* 输出类型的缓存 */
			TupleConversionMap *map;	/* 列映射 */
		}			convert_rowtype;

		/* 对于 EEOP_SCALARARRAYOP */
		struct
		{
			/* element_type/typlen/typbyval/typalign 在运行时填写 */
			Oid			element_type;	/* 如果尚未填写则为 InvalidOid */
			bool		useOr;	/* 使用 OR 或 AND 语义？ */
			int16		typlen; /* 数组元素类型存储信息 */
			bool		typbyval;
			char		typalign;
			FmgrInfo   *finfo;	/* 函数的查找数据 */
			FunctionCallInfo fcinfo_data;	/* 参数等 */
			/* 无需额外间接访问的更快访问方式： */
			PGFunction	fn_addr;	/* 实际调用地址 */
		}			scalararrayop;

		/* 对于 EEOP_HASHED_SCALARARRAYOP */
		struct
		{
			bool		has_nulls;
			bool		inclause;	/* 对于 IN 为 true，对应 NOT IN 为 false */
			struct ScalarArrayOpExprHashTable *elements_tab;
			FmgrInfo   *finfo;	/* 函数的查找数据 */
			FunctionCallInfo fcinfo_data;	/* 参数等 */
			ScalarArrayOpExpr *saop;
		}			hashedscalararrayop;

		/* 对于 EEOP_XMLEXPR */
		struct
		{
			XmlExpr    *xexpr;	/* 原始表达式节点 */
			/* 评估命名参数的工作空间（如果有） */
			Datum	   *named_argvalue;
			bool	   *named_argnull;
			/* 评估未命名参数的工作空间（如果有） */
			Datum	   *argvalue;
			bool	   *argnull;
		}			xmlexpr;

		/* 对于 EEOP_AGGREF */
		struct
		{
			int			aggno;
		}			aggref;

		/* 对于 EEOP_GROUPING_FUNC */
		struct
		{
			List	   *clauses;	/* 整数列的列编号 */
		}			grouping_func;

		/* 对于 EEOP_WINDOW_FUNC */
		struct
		{
			/* 非行内状态，由 nodeWindowAgg.c 修改 */
			WindowFuncExprState *wfstate;
		}			window_func;

		/* 对于 EEOP_SUBPLAN */
		struct
		{
			/* 非行内状态，由 nodeSubplan.c 创建 */
			SubPlanState *sstate;
		}			subplan;

		/* 对于 EEOP_AGG_*DESERIALIZE */
		struct
		{
			FunctionCallInfo fcinfo_data;
			int			jumpnull;
		}			agg_deserialize;

		/* 对于 EEOP_AGG_STRICT_INPUT_CHECK_NULLS / STRICT_INPUT_CHECK_ARGS */
		struct
		{
			/*
			 * 对于 EEOP_AGG_STRICT_INPUT_CHECK_ARGS，args 包含指向需要
			 * 检查 NULL 的 NullableDatums 的指针。
			 *
			 * 对于 EEOP_AGG_STRICT_INPUT_CHECK_NULLS，nulls 包含指向
			 * 需要检查 NULL 的布尔值的指针。
			 *
			 * 这两种情况目前都需要存在，因为有时待检查的 nulls 在
			 * TupleTableSlot.isnull 数组中，有时在 FunctionCallInfoBaseData.args[i].isnull 中。
			 */
			NullableDatum *args;
			bool	   *nulls;
			int			nargs;
			int			jumpnull;
		}			agg_strict_input_check;

		/* 对于 EEOP_AGG_PLAIN_PERGROUP_NULLCHECK */
		struct
		{
			int			setoff;
			int			jumpnull;
		}			agg_plain_pergroup_nullcheck;

		/* 对于 EEOP_AGG_PLAIN_TRANS_[INIT_][STRICT_]{BYVAL,BYREF} */
		/* 对于 EEOP_AGG_ORDERED_TRANS_{DATUM,TUPLE} */
		struct
		{
			AggStatePerTrans pertrans;
			ExprContext *aggcontext;
			int			setno;
			int			transno;
			int			setoff;
		}			agg_trans;
	}			d;
} ExprEvalStep;


/* 容器操作的非行内数据 */
typedef struct SubscriptingRefState
{
	bool		isassignment;	/* 是赋值，还是仅仅取值？ */

	/* workspace for type-specific subscripting code */
	void	   *workspace;

	/* numupper 和 upperprovided[] 在表达式编译时填充 */
	/* 在运行时，子脚本在 upperindex[]/upperindexnull[] 中计算 */
	int			numupper;
	bool	   *upperprovided;	/* 表示此位置是否已提供 */
	Datum	   *upperindex;
	bool	   *upperindexnull;

	/* 对于 lower indexes 也是类似，若有的话 */
	int			numlower;
	bool	   *lowerprovided;
	Datum	   *lowerindex;
	bool	   *lowerindexnull;

	/* 对于赋值，要赋的新值在这里进行评估 */
	Datum		replacevalue;
	bool		replacenull;

	/* 如果我们有一个嵌套赋值，sbs_fetch_old 将旧值放在这里 */
	Datum		prevvalue;
	bool		prevnull;
} SubscriptingRefState;

/* 用于 SubscriptingRef 的执行步骤方法 */
typedef struct SubscriptExecSteps
{
	/* 有关这些的更多详细信息，请参见 nodes/subscripting.h */
	ExecEvalBoolSubroutine sbs_check_subscripts;	/* 处理子脚本 */
	ExecEvalSubroutine sbs_fetch;	/* 获取一个元素 */
	ExecEvalSubroutine sbs_assign;	/* 给一个元素赋值 */
	ExecEvalSubroutine sbs_fetch_old;	/* 获取赋值的旧值 */
} SubscriptExecSteps;


/* execExpr.c 中的函数 */
extern void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s);

/* execExprInterp.c 中的函数 */
extern void ExecReadyInterpretedExpr(ExprState *state);
extern ExprEvalOp ExecEvalStepOp(ExprState *state, ExprEvalStep *op);

extern Datum ExecInterpExprStillValid(ExprState *state, ExprContext *econtext, bool *isNull);
extern void CheckExprStillValid(ExprState *state, ExprContext *econtext);

/*
 * 非快速路径执行函数。这些在 execExprInterp.c 中是 extern 而不是 static，
 * 因为这使它们可以被其他表达式评估方法使用，从而减少代码重复。
 */
extern void ExecEvalFuncExprFusage(ExprState *state, ExprEvalStep *op,
								   ExprContext *econtext);
extern void ExecEvalFuncExprStrictFusage(ExprState *state, ExprEvalStep *op,
										 ExprContext *econtext);
extern void ExecEvalParamExec(ExprState *state, ExprEvalStep *op,
							  ExprContext *econtext);
extern void ExecEvalParamExtern(ExprState *state, ExprEvalStep *op,
								ExprContext *econtext);
extern void ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op);
extern void ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *op);
extern void ExecEvalNextValueExpr(ExprState *state, ExprEvalStep *op);
extern void ExecEvalRowNull(ExprState *state, ExprEvalStep *op,
							ExprContext *econtext);
extern void ExecEvalRowNotNull(ExprState *state, ExprEvalStep *op,
							   ExprContext *econtext);
extern void ExecEvalArrayExpr(ExprState *state, ExprEvalStep *op);
extern void ExecEvalArrayCoerce(ExprState *state, ExprEvalStep *op,
								ExprContext *econtext);
extern void ExecEvalRow(ExprState *state, ExprEvalStep *op);
extern void ExecEvalMinMax(ExprState *state, ExprEvalStep *op);
extern void ExecEvalFieldSelect(ExprState *state, ExprEvalStep *op,
								ExprContext *econtext);
extern void ExecEvalFieldStoreDeForm(ExprState *state, ExprEvalStep *op,
									 ExprContext *econtext);
extern void ExecEvalFieldStoreForm(ExprState *state, ExprEvalStep *op,
								   ExprContext *econtext);
extern void ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op,
								   ExprContext *econtext);
extern void ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op);
extern void ExecEvalHashedScalarArrayOp(ExprState *state, ExprEvalStep *op,
										ExprContext *econtext);
extern void ExecEvalConstraintNotNull(ExprState *state, ExprEvalStep *op);
extern void ExecEvalConstraintCheck(ExprState *state, ExprEvalStep *op);
extern void ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op);
extern void ExecEvalGroupingFunc(ExprState *state, ExprEvalStep *op);
extern void ExecEvalSubPlan(ExprState *state, ExprEvalStep *op,
							ExprContext *econtext);
extern void ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op,
								ExprContext *econtext);
extern void ExecEvalSysVar(ExprState *state, ExprEvalStep *op,
						   ExprContext *econtext, TupleTableSlot *slot);

extern void ExecAggInitGroup(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroup,
							 ExprContext *aggcontext);
extern Datum ExecAggTransReparent(AggState *aggstate, AggStatePerTrans pertrans,
								  Datum newValue, bool newValueIsNull,
								  Datum oldValue, bool oldValueIsNull);
extern void ExecEvalAggOrderedTransDatum(ExprState *state, ExprEvalStep *op,
										 ExprContext *econtext);
extern void ExecEvalAggOrderedTransTuple(ExprState *state, ExprEvalStep *op,
										 ExprContext *econtext);

#endif							/* EXEC_EXPR_H */
